(define square
  (lambda (x) (* x x)))

(define sum-squares
  (lambda (lst)
    (if (null? lst)
        0
        (+ (square (car lst))
           (sum-squares (cdr lst))))))

(define norm
  (lambda points
    (sqrt (sum-squares points))))

(define list-reduce
  (lambda (proc default lista)
    
    (letrec ((really-reduce
              (lambda (proc lista)
                (if (= 1 (length lista))
                    (car lista)
                    (proc (car lista)
                          (really-reduce proc
                                         (cdr lista)))))))
      (if (null? lista)
          default
          (really-reduce proc lista)))))

(define make-rectangular
  (lambda (a b)
    (list a b)))

(define complex?
  (lambda (x)
    (and (list? x)
         (number? (car x))
         (number? (cadr x)))))

(define real-part
  (lambda (c)
    (car c)))

(define imag-part
  (lambda (c)
    (cadr c)))

(define complex=
  (lambda (z1 z2)
    (and (= (real-part z1)
            (real-part z2))
         (= (imag-part z1)
            (imag-part z2)))))

(define standard+ +)
(define standard* *)

(define real->complex
  (lambda (x)
    (if (complex? x)
        x
        (make-rectangular x 0))))

(define complex+
  (lambda (x y)
    (let ((complex-x (real->complex x))
          (complex-y (real->complex y)))
      (let ((a (real-part complex-x))
            (b (imag-part complex-x))
            (c (real-part complex-y))
            (d (imag-part complex-y)))
        (make-rectangular (+ a c) (+ b d))))))

(define binary+
  (lambda (a b)
    (if (or (complex? a)
            (complex? b))
        (complex+ a b)
        (standard+ a b))))

(define n-ary+
  (lambda args
    (list-reduce binary+ 0 args)))

(n-ary+ 2 3 (make-rectangular 1 5))

(define + n-ary+)
(+ 7 (make-rectangular 0 2))

(define complex*
  (lambda (x y)
    (let ((complex-x (real->complex x))
          (complex-y (real->complex y)))
      (let ((a (real-part complex-x))
            (b (imag-part complex-x))
            (c (real-part complex-y))
            (d (imag-part complex-y)))
        (make-rectangular (- (* a c) (* b d))
                          (+ (* b c) (* a d)))))))

(define binary*
  (lambda (a b)
    (if (or (complex? a)
            (complex? b))
        (complex* a b)
        (standard* a b))))

(define n-ary*
  (lambda args
    (list-reduce binary* 1 args)))

(define * n-ary*)

(define magnitude
  (lambda (args)
    (norm (car args)
          (cadr args))))

(define ang
  (lambda (c)
    (atan (/ (imag-part c)
             (real-part c)))))
  
